#ifndef MAT4_HPP_
#define MAT4_HPP_

#include "Vec4.hpp"
#include <string>
#include <iostream>
#include <cmath>

using std::sqrt;

namespace gmath
{
  template <class T, short S> class Mat4
  {
    public:
      union
      {
        T v_[S][S];
        T m_[S * S];
      };

      Mat4();
      Mat4(T diagonal);
      Mat4(T* m);

      void identity();
      Mat4 transpose();
      Mat4 inverse();
      T determinant();
      Mat4 mul(Mat4& m2);
      Mat4 mul(T a);

      std::string toString();
      static std::string toString(T** m, short col_count);
      
      Mat4 operator*(T a);
      Mat4 operator*(Mat4& m2);

      template<typename J, short K> friend std::ostream& 
          operator<<(std::ostream& out, Mat4<J, K> m);

    private:
      void diagonal(T value);
      T determinant(T** m, short col_count);
      T** minorM(T** m, short col_count, short col_idx, short row_idx);
      Mat4 matrixOfMinors();
      Mat4 matrixOfCofactors();
      T** allocateMatrix();
  };

  typedef Mat4<float, 4> Mat4f;
  typedef Mat4<double, 4> Mat4d;
}

#include "Mat4.inl"

#endif
